package si.banst.statistika.ejb;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.annotation.security.RolesAllowed;
import javax.ejb.EJBException;
import javax.ejb.LocalBean;
import javax.ejb.Schedule;
import javax.ejb.Stateless;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.ws.WebServiceRef;
import javax.xml.ws.soap.Addressing;

import si.banst.statistika.DateUtil;
import si.banst.statistika.entitete.Tecaj;
import si.banst.statistika.entitete.TecajID;
import si.banst.statistika.entitete.Valuta;
import si.banst.statistika.entitete.VrstaTecajnice;
import si.banst.tecajnice.storitve.TecajType;
import si.banst.tecajnice.storitve.TecajnicaType;
import si.banst.tecajnice.storitve.ValutaType;
import si.banst.tecajnice.storitve.VrstaTecajniceType;
import si.banst.tecajnice.storitve.tecajnicestoritev.TecajniceStoritev;
import si.banst.tecajnice.storitve.tecajnicestoritev.TecajniceStoritev_Service;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniTecajniceRezultat;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniTecajniceZahteva;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniTecajniceZahteva.Datumi;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniTecajniceZahteva.Valute;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniTecajniceZahteva.VrsteTecajnic;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniValuteRezultat;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniValuteZahteva;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniVrsteTecajnicRezultat;
import si.banst.tecajnice.storitve.tecajnicestoritev.VrniVrsteTecajnicZahteva;

import com.hazelcast.core.Hazelcast;

/**
 * Session Bean implementation class TecajiPomnilnikBean
 */
@Stateless
@LocalBean
@RolesAllowed({ "Referent", "PoslovniPartner" })
public class TecajiBean {

	private static final Logger logger = Logger.getLogger(TecajiBean.class
			.getName());

	@Addressing
	@WebServiceRef(wsdlLocation = "http://tecajniceweb.banst.si:9081/tecajnice-storitve/TecajniceStoritev?wsdl")
	private TecajniceStoritev_Service tecajniceStoritev_Service;

	private static Map<Integer, Valuta> valute;

	private static Map<Integer, VrstaTecajnice> vrsteTecajnic;

	private Map<TecajID, Tecaj> tecajiPomnilnik;

	public TecajiBean() {
		super();
	}

	@PostConstruct
	public void init() {
		try {
			logger.info("Inicialiiram TecajiBean. ");
			logger.fine("Povezujem s Hazelcast. ");
			tecajiPomnilnik = Hazelcast.getMap("tecaj");

			if (tecajniceStoritev_Service == null)
				throw new Exception(
						"Napaka pri inicializaciji. TecajniceStoritev je null. ");

			if (valute == null)
				napolniValute();
			if (vrsteTecajnic == null)
				napolniVrsteTecajnic();

		} catch (Exception e) {
			logger.severe("Napaka pri inicializaciji. " + e.getMessage());
			throw new EJBException("Napaka pri inicializaciji. ", e);
		}
	}

	public List<Tecaj> vrniTecaje(Date datumOd, Date datumDo,
			Integer sifraVrsteTecajnice, Integer sifraValute) throws Exception {
		logger.fine("V medpomnilniku je " + tecajiPomnilnik.size()
				+ " tecajev. ");
		try {
			logger.fine("Klic metode vrniTecaje. ");
			List<Tecaj> tecaji = new ArrayList<Tecaj>();
			VrniTecajniceZahteva vrniTecajniceZahteva = new VrniTecajniceZahteva();
			Datumi datumi = new Datumi();
			vrniTecajniceZahteva.setDatumi(datumi);

			Valute v = new Valute();
			v.getSifra().add(sifraValute);
			vrniTecajniceZahteva.setValute(v);

			VrsteTecajnic vt = new VrsteTecajnic();
			vt.getSifraVrsteTecajnice().add(sifraVrsteTecajnice);
			vrniTecajniceZahteva.setVrsteTecajnic(vt);

			Calendar koledarDo = Calendar.getInstance();
			koledarDo.setTime(DateUtil.nastaviCasNaPolnoc(datumDo));

			Calendar koledarOd = Calendar.getInstance();
			koledarOd.setTime(DateUtil.nastaviCasNaPolnoc(datumOd));

			while (koledarOd.before(koledarDo)) {
				if ((koledarOd.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
						|| (koledarOd.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)) {
					koledarOd.add(Calendar.DATE, 1);
					continue;
				}
				TecajID tecajID = new TecajID(koledarOd.getTime(),
						sifraVrsteTecajnice, sifraValute);
				Tecaj tp = tecajiPomnilnik.get(tecajID);
				if (tp != null)
					tecaji.add(tp);
				else {
					GregorianCalendar gregorianCalendar = new GregorianCalendar();
					gregorianCalendar.setTime(koledarOd.getTime());
					XMLGregorianCalendar xmlGregorianCalendar = DatatypeFactory
							.newInstance().newXMLGregorianCalendar(
									gregorianCalendar);
					datumi.getDatum().add(xmlGregorianCalendar);
				}
				koledarOd.add(Calendar.DATE, 1);
			}
			logger.fine("Iz pomnilnika prevzeto tecajev:" + tecaji.size());
			logger.fine("Preostalo tecajev: "
					+ vrniTecajniceZahteva.getDatumi().getDatum().size());
			if (datumi.getDatum().isEmpty())
				return tecaji;

			TecajniceStoritev tecajniceStoritev = tecajniceStoritev_Service
					.getTecajniceStoritevSOAP();

			VrniTecajniceRezultat vrniTecajniceRezultat = tecajniceStoritev
					.vrniTecajnice(vrniTecajniceZahteva);

			for (TecajnicaType tecajnica : vrniTecajniceRezultat.getTecajnica()) {
				for (TecajType tec : tecajnica.getTecaj()) {
					TecajID tId = new TecajID(tecajnica.getDatumTecajnice()
							.toGregorianCalendar().getTime(), tecajnica
							.getVrstaTecajnice().getSifra(), tec.getValuta()
							.getSifra());
					Tecaj tecaj = new Tecaj();
					tecaj.setId(tId);
					tecaj.setDatumCasSpremembe(new Date());
					tecaj.setNakupniTecaj(tec.getNakupniTecaj());
					tecaj.setSrednjiTecaj(tec.getSrednjiTecaj());
					tecaj.setProdajniTecaj(tec.getProdajniTecaj());

					tecaji.add(tecaj);
					tecajiPomnilnik.put(tId, tecaj);
				}
			}

			Collections.sort(tecaji, tecajCompare);

			return tecaji;
		} catch (Exception e) {
			logger.severe("Napaka pri povprasevanju" + e.getMessage());
			throw new Exception("Napaka pri poizvedbi. ", e);
		}

	}

	@Schedule(hour = "*/2")
	public void napolniVrsteTecajnic() {
		try {
			logger.info("Polnim vrste tecajnic");
			if (vrsteTecajnic == null)
				vrsteTecajnic = new HashMap<Integer, VrstaTecajnice>();
			else
				vrsteTecajnic.clear();

			TecajniceStoritev tecajniceStoritev = tecajniceStoritev_Service
					.getTecajniceStoritevSOAP();
			VrniVrsteTecajnicRezultat rezultat = tecajniceStoritev
					.vrniVrsteTecajnic(new VrniVrsteTecajnicZahteva());
			for (VrstaTecajniceType vt : rezultat.getVrstaTecajnice()) {
				VrstaTecajnice vrstaTecajnice = new VrstaTecajnice();
				vrstaTecajnice.setNazivVrsteTecajnice(vt.getNaziv());
				vrstaTecajnice.setDatumCasSpremembe(new Date());
				vrstaTecajnice.setSifraVrsteTecajnice(vt.getSifra());
				vrsteTecajnic.put(vrstaTecajnice.getSifraVrsteTecajnice(),
						vrstaTecajnice);
			}
			logger.info("Dodano " + vrsteTecajnic.size() + " vrst tecajnic. ");
		} catch (Exception e) {
			logger.severe("Napaka pri zapisu vrst tecajnic. " + e.getMessage());
			throw new EJBException("Napaka pri zapisu vrst tecajnic. ", e);
		}
	}

	@Schedule(hour = "*/2")
	public void napolniValute() {
		try {
			logger.info("Polnim valute");
			if (valute == null)
				valute = new HashMap<Integer, Valuta>();
			else
				valute.clear();

			TecajniceStoritev tecajniceStoritev = tecajniceStoritev_Service
					.getTecajniceStoritevSOAP();
			VrniValuteRezultat rezultat = tecajniceStoritev
					.vrniValute(new VrniValuteZahteva());
			for (ValutaType v : rezultat.getValuta()) {
				Valuta valuta = new Valuta();
				valuta.setDatumCasSpremembe(new Date());
				valuta.setOznakaDrzave(v.getDrzava().getOznaka());
				valuta.setOznakaValute(v.getOznaka());
				valuta.setSifraValute(v.getSifra());
				valute.put(valuta.getSifraValute(), valuta);
			}
			logger.info("Dodano " + valute.size() + " valut. ");
		} catch (Exception e) {
			logger.severe("Napaka pri zapisu vrst tecajnic. " + e.getMessage());
			throw new EJBException("Napaka pri zapisu vrst tecajnic. ", e);
		}
	}

	public Map<Integer, Valuta> getValute() {
		return valute;
	}

	public Map<Integer, VrstaTecajnice> getVrsteTecajnic() {
		return vrsteTecajnic;
	}

	public Valuta getValuta(Integer sifraValute) {
		return valute.get(sifraValute);
	}

	public VrstaTecajnice getVrstaTecajnice(Integer sifraVrsteTecajnice) {
		return vrsteTecajnic.get(sifraVrsteTecajnice);
	}

	private static final Comparator<Tecaj> tecajCompare = new Comparator<Tecaj>() {
		@Override
		public int compare(Tecaj o1, Tecaj o2) {
			if (DateUtil.nastaviCasNaPolnoc(o1.getId().getDatumTecajnice())
					.equals(DateUtil.nastaviCasNaPolnoc(o2.getId()
							.getDatumTecajnice())))
				return 0;

			if (DateUtil.nastaviCasNaPolnoc(o1.getId().getDatumTecajnice())
					.before(DateUtil.nastaviCasNaPolnoc(o2.getId()
							.getDatumTecajnice())))
				return -1;
			else
				return 1;
		}
	};

}
